package com.xjrsoft.common.handler;

import com.xjrsoft.common.result.Response;
import com.xjrsoft.common.result.ResultCode;
import com.xjrsoft.common.utils.IpUtil;
import com.xjrsoft.core.secure.utils.SecureUtil;
import com.xjrsoft.core.tool.utils.WebUtil;
import com.xjrsoft.module.base.entity.XjrBaseLog;
import com.xjrsoft.module.base.service.IXjrBaseLogService;
import com.xjrsoft.module.base.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.*;

@ControllerAdvice
@Slf4j
public class MyExceptionHandler {

	@Value("${xjrsoft.global-config.exceptionEnabled}")
	private boolean exceptionEnabled;

	@Autowired
	private IXjrBaseLogService logService;


	/**
	 * 请求方式不支持
	 */
	@ResponseBody
	@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
	public Response handleException(HttpRequestMethodNotSupportedException e) {
		log.error("HttpRequestMethodNotSupportedException Exception Cause by:{}",e.getMessage());
		return Response.notOk("方法不支持‘" + e.getMethod() + "'请求");
	}

	/**
	 * 拦截未知的运行时异常
	 */
	@ResponseBody
	@ExceptionHandler(RuntimeException.class)
	public Response notFount(RuntimeException e) {
		log.error("RuntimeException Exception Cause by:{}",e.getMessage(),e);
		return Response.notOk("运行时异常");
	}


	/**
	 * 校验异常
	 */
	@ResponseBody
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	public Response exceptionHandler(MethodArgumentNotValidException e) {
		BindingResult bindingResult = e.getBindingResult();
		String errorMesssage = "";
		for (FieldError fieldError : bindingResult.getFieldErrors()) {
			errorMesssage += fieldError.getField()+fieldError.getDefaultMessage() + "!";
		}
		log.error("MethodArgumentNotValidException Exception Cause by:{}",errorMesssage);
		return Response.notOk("参数校验失败");
	}

	/**
	 * 校验异常
	 */
	@ResponseBody
	@ExceptionHandler(value = BindException.class)
	public Response validationExceptionHandler(BindException e) {
		BindingResult bindingResult = e.getBindingResult();
		List<String> errorMesssage = new ArrayList<>();
		for (FieldError fieldError : bindingResult.getFieldErrors()) {
			errorMesssage.add(fieldError.getField());
		}
		log.error("BindException Exception Cause by:{}",errorMesssage);
		return Response.notOk(errorMesssage,"参数校验失败");
	}

	/**
	 * 校验异常
	 */
	@ResponseBody
	@ExceptionHandler(value = ConstraintViolationException.class)
	public Response ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
		Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
		Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
		List<String> msgList = new ArrayList<>();
		while (iterator.hasNext()) {
			ConstraintViolation<?> cvl = iterator.next();
			msgList.add(cvl.getMessageTemplate());
		}
		return Response.notOk("参数校验失败");
	}
	/**
	 * @处理404异常
	 * @param req
	 * @param e
	 * @return
	 */
	@ResponseBody
	@ExceptionHandler(NoHandlerFoundException.class)
	public Response handlerNoFoundException(HttpServletRequest req, NoHandlerFoundException e) {
		log.error("NoHandlerFoundException Exception Cause by:{}", e.getMessage());
		return Response.notOk(ResultCode.NOT_FOUND.getCode(),ResultCode.NOT_FOUND.getMessage());
	}

	/**
	 * @param req
	 * @param e
	 * @return
	 * @处理：空指针异常
	 */
	@ResponseBody
	@ExceptionHandler(NullPointerException.class)
	public Response nullPointerExceptionHandler(HttpServletRequest req, NullPointerException e)
	{
		log.error("NullPointerException Exception Cause by:{}", e.getMessage());
		return Response.notOk("NullPointerException Exception");
	}
	@ResponseBody
	@ExceptionHandler(StringIndexOutOfBoundsException.class)
	public Response stringIndexOutOfBoundsException(HttpServletRequest req, Exception e)
	{
		log.error("stringIndexOutOfBoundsException Exception Cause by:{}", e.getMessage());
		return Response.notOk("字符串越界");
	}

	@ResponseBody
	@ExceptionHandler(Exception.class)
	public Response exceptionHandler(Exception e){
		String errMsg = e.getMessage() == null ? e.toString() : e.getMessage();
		log.error("内部服务器错误！", e);
		// 保存异常日志
		XjrBaseLog log = buildLog(errMsg);
		logService.addLog(log);
		if(exceptionEnabled){
			return Response.notOk(ResultCode.INTERNAL_SERVER_ERROR.getCode(), ResultCode.NOT_FOUND.getMessage());
		}

		return Response.notOk(ResultCode.INTERNAL_SERVER_ERROR.getCode(), errMsg);
	}
    private XjrBaseLog buildLog(String errMsg) {
		HttpServletRequest request = WebUtil.getRequest();
		XjrBaseLog log = new XjrBaseLog();

		assert request != null;
		log.setCategoryId(4);
		log.setHost(request.getRemoteHost());
		log.setOperateAccount(SecureUtil.getUserAccount());
		log.setOperateTime(LocalDateTime.now());
		log.setOperateUserId(SecureUtil.getUserId());
		log.setIpAddress(IpUtil.getIpAddr(request));
		log.setOperateType(LogUtil.getOperateType(request).getValue());
		log.setOperateTypeId(Integer.toString(LogUtil.getOperateType(request).getCode()));
		log.setExecuteResult(-1);
		log.setExecuteResultJson(errMsg);
		log.setBrowser(LogUtil.getBrowser((request.getHeader("user-agent"))));
//		log.setModule(methodName);
		return log;
	}

}